<?php
//Конструктор запросов
class q {
    //Здесь хранится текущий запрос
    //Можно было бы назвать переменную $query
    //Но она названа так для возможности использовать гиковскую запись:
    //q::ini('smth')->select()->end
    public $end = '';
    
    //Информация о таблице, с которой идёт работа
    private $dbf, $tbl;
    //private $tieInfo;    
    
    //Было ли уже добавлено хоть одно условие where
    private $where_on = FALSE;
    
    //Инициализация запроса, указывается имя таблицы и префикс полей
    static function ini($tbl, $dbf = '') {
        $q = new q();
        $q->_init($tbl, $dbf);
        return $q;
    }
    
    //Инициализация запроса, указывается класс,
    //с которым будет производится работа
    static function obj($class_name, $tie = FALSE) {
        extract(Object::getDBInfo($class_name));
        $q = new q();
        $q->_init($table_name, $field_prefix, $tie);
        return $q;
    }
    /*
    //Инициализация запроса для работы с таблицей связей
    static function tie($tie) {
        $q = new q();
        $q->_init('', '', $tie);
        return $q;
    }    
    */
    function _init($tbl, $dbf, $tie = FALSE) {
        $this->tbl = '`?_'.$tbl.'`';
        $this->dbf = $dbf;
        /*
        if ($tie) {
            $this->tieInfo = $tie->getDBInfo();
            if (!$tbl)
                $this->tbl = '`'.$this->tieInfo['tie_table'].'`';
        }*/
    }
   
    public function select($fields = FALSE, $escape = TRUE) {
            
        if ($fields)
            if ($escape)
                $what = $this->comma_fields($fields);
            else
                $what = $fields;
        else
            $what = '*';
        
        $this->end .= 'SELECT '.$what.' FROM '.$this->tbl.' ';
        
        return $this;
    }
    
    public function insert($fields) {
        $keys = array_keys($fields);
        $values = array(array_values($fields));
    
	    $this->end .= $this->insertMany($keys, $values);
        
        return $this;
    }
    
    
    public function insertMany($fields, $values) {
        $new_values = array();
        foreach ($values as $row_values)
            $new_values[] = '('.$this->comma_values($row_values).')';
        
        $values = implode(',', $new_values);
        $query .= 'INSERT INTO '.$this->tbl.' ('.$this->comma_fields($fields).') VALUES '.$values;
        
        return $query;
    }
    
	public function limit($num) {
		$this->end .= 'LIMIT '.$num.' ';
		return $this;
	}
	
    public function update($fields) {
        $this->end = 'UPDATE '.$this->tbl.' SET ';
        $keys = $this->fields(array_keys($fields));
        $values = $this->values(array_values($fields));
        
        $updates = array();
        while ($keys)
            $updates[] = array_shift($keys).' = '.array_shift($values);
            
        $this->end .= implode(',', $updates).' ';
        
        return $this;    
    }
    
    public function delete() {
        $this->end = 'DELETE FROM '.$this->tbl.' ';
        return $this;
    }
	
	public function drop() {
		$this->end = 'DROP TABLE IF EXISTS '.$this->tbl;
		return $this;
	}
    
	public function create($fields) {
		$query = 'CREATE TABLE '.$this->tbl.' (`'.$this->dbf.'id` INT UNSIGNED NOT NULL AUTO_INCREMENT,';
         
        foreach ($fields as $field_name=>$field) {
            
            $maxlength = '';
            $notnull = '';
            $default = '';
            
            //if(isset($field['maxlength']))
            //    $maxlength = ' ('.$field['maxlength'].')';
                
            if ($field['not_null'])
                $notnull = ' NOT NULL';                          
            
            if (isset($field['default']))
                $default = ' DEFAULT `'.$field['default'].'`';

            if (in_array($field['type'], array('string', 'image', 'file', 'list')))
				$type = 'VARCHAR(255)';
				
            if (in_array($field['type'], array('text', 'html', 'files', 'images')))
		        $type = 'TEXT';
			
			if ($field['type'] == 'date')
			    $type = 'DATETIME';
			
			if ($field['type'] == 'bool')
                $type = 'TINYINT(1)';
            			
			
			$query .= '`'.$this->dbf.$field_name.'` '.$type.$notnull.$default.', ';
            
            //$query .= '`'.$field_prefix.$field_name.'` '.$type.$maxlength.$notnull.$default.' ,';
        }   
        /*
        if ($updated) {
            $query .= '`'.$field_prefix.'updated` TIMESTAMP DEFAULT \'0000-00-00 00:00:00\' ON UPDATE CURRENT_TIMESTAMP,';
        }
        
        if ($created) {
            $query .= '`'.$field_prefix.'created` TIMESTAMP,';
        }*/
        
        $query .= 'PRIMARY KEY ( `'.$this->dbf.'id` ))';
        $this->end = $query;
		return $this;
	}
	
    public function where($field, $value, $prefix = TRUE) {
        $where_condition = $this->field($field, $prefix).' = '.$this->value($value);
        return $this->add_where($where_condition);
    }
    
    public function like($field, $cond, $prefix = TRUE) {
        $where_cond = $this->field($field, $prefix).' LIKE '.$this->value($cond);
        return $this->add_where($where_cond);
    }
   
    public function innerJoin($table, $field_1, $field_2) {
        $this->end .= 'INNER JOIN '.$this->table($table).' ON `'.$field_1.'` = `'.$field_2.'` ';
        return $this;
    }
   
    
    public function where_in($field, $values, $is_array = TRUE) {
        if ($is_array)
            $values = $this->comma_values($values);
        
        $where_condition = $this->field($field).' IN ('.$values.')';
        
        return $this->add_where($where_condition);
    }
    
	public function or_where($field, $value, $prefix = TRUE) {
		$where_condition = $this->field($field, $prefix).' = '.$this->value($value);
        return $this->add_where($where_condition, 'OR');
	}
	
    private function add_where($where_condition, $operation = 'AND') {
        if ($this->where_on) 
            $this->end .= $operation.' '.$where_condition.' ';
        else {
            $this->end .= 'WHERE '.$where_condition.' ';
            $this->where_on = TRUE;
        }
        return $this;
    }
    /*
    //Join с таблицей связей
    public function joinOwnerTies() {
        extract($this->tieInfo);        
        $this->end .= 'JOIN '.$tie_table.' ON `'.$child_dbf.'id` = `'.$child_field.'` ';
        return $this;
    }
    
    //Join c сущностью по связи
    public function joinChilds() {
        extract($this->tieInfo);
        $this->end .= 'LEFT JOIN `'.$child_table.'` ON `'.$child_dbf.'id` = `'.$child_field.'` ';
        return $this;
    }
    
    public function whereOwners($ids) {
        extract($this->tieInfo);
        return $this->where_in($owner_field, $ids, FALSE);
    }
    
    
    //Ограничение на таблицу связей, $id владельца должен быть $id
    public function whereOwner($id) {
        extract($this->tieInfo);
        $this->where($owner_field, $id, FALSE);
        return $this;
    }
    */
    private function field($field, $prefix = TRUE) {
        if ($prefix)
            $field = $this->dbf.$field;
        return '`'.$field.'`';
    }
    
    private function fields($fields) {
        $fields = var2array($fields);
        $new_fields = array();
        foreach ($fields as $field)
            $new_fields[] = '`'.$this->dbf.$field.'`';
        return $new_fields;
    }
      
    private function comma_fields($fields) {
        return implode(',', $this->fields($fields));
    }
    
	private function table($table_name) {
        return '`?_'.$table_name.'`';
    }
    
    private function value($value) {
        if (is_bool($value))
            $value = ($value == FALSE)? 0 : 1;
        else if (is_null($value))
            $value = 'NULL';
        else
            $value = "'".mysql_real_escape_string($value)."'";
            
        return $value;
    }
    
    private function values($values) {
        $values = var2array($values);
        $result = array();      
        foreach ($values as $value) {
            if (is_bool($value))
                $value = ($value == FALSE)? 0 : 1;
            else if (is_null($value))
                $value = 'NULL';
            else
                $value = "'".mysql_real_escape_string($value)."'";

            $result[] = $value;
        }
        return $result;
    }
    
    private function comma_values($values) {
        return implode(',', $this->values($values));;
    }
	
	//Набор готовых запросов
	public static function count() {
		return 'SELECT FOUND_ROWS() as num';
	}
}

/*
//Класс содержит в себе ряд полезных готовых запросов
class Query {
    //Аццкий запрос для поиска задач по тегам
    static function getProblemsByTagIds($tag_ids) {
        $query = 'SELECT `prb_id` AS `id` FROM (';
            $query .= 'SELECT `prb_id`, COUNT(`prb_id`) as `prb_num` FROM (';
                $query .= 'SELECT `pht_o_problems_id` AS `prb_id` FROM `problems_tie_tags` WHERE `pht_c_tags_id` IN ('.implode($tag_ids,',').')';
            $query .= ') as `first`';
            $query .= 'GROUP BY `prb_id`';
        $query .= ') as `second` ';
        $query .= 'WHERE `prb_num` = '.count($tag_ids);
        return $query;
    }
    
    public static function set_db_collation() {
        return 'ALTER DATABASE `problems` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci';
    }
    
    public static function object_create($table_name, $field_prefix, $fields, $created = false, $updated = false) {
     
    }
    
    public static function selectObject($id, $table_name, $dbf) {
        return 'SELECT * FROM `'.$table_name.'` WHERE `'.$dbf.'id` = '.Query::escape_value($id);
    }
    
    public static function select($class_name) {
        $qc = new QueryConstructor();
        return $qc->select($class_name);
    }

        public static function create($table_name, $field_prefix, $fields, $auto_increment = '', $created = false, $updated = false) {
        if ($auto_increment)
          $auto_increment = ' AUTO_INCREMENT';
          
        $query = 'CREATE TABLE `'.$table_name.'` (`'.$field_prefix.'id` INT NOT NULL'.$auto_increment.',';
        
        foreach ($fields as $field_name=>$field) {
            
            $maxlength = '';
            $notnull = '';
            $default = '';
            $on_update = '';
            
            if(isset($field['maxlength']))
                $maxlength = ' ('.$field['maxlength'].')';
                
            if (!$field['null'])
                $notnull = ' NOT NULL';                          
            
            $type = $field['type'];
            
            if (isset($field['default'])) {
                if ($field['default'][0] == '@')
                    $default = " DEFAULT ".cutFirst($field['default']);
                else
                    $default = " DEFAULT '".$field['default']."'";
            }
            
             if (isset($field['on_update']))
                $default = " ON UPDATE ".$field['on_update']; 
            
            $query .= '`'.$field_prefix.$field_name.'` '.$type.$maxlength.$notnull.$default.' ,';
        }   

        if ($updated) {
            $query .= '`'.$field_prefix.'updated` TIMESTAMP DEFAULT \'0000-00-00 00:00:00\' ON UPDATE CURRENT_TIMESTAMP,';
        }
        
        if ($created) {
            $query .= '`'.$field_prefix.'created` TIMESTAMP,';
        }
       
        $query .= 'PRIMARY KEY ( `'.$field_prefix.'id` ));';
        return $query;
    }    

    public static function delete($table_name, $conditions) {
        $qc = new QueryConstructor();
        return $qc->delete($table_name)->where($conditions)->get();
    }

    public static function insert($table_name, $fields) {
        print_r($fields);
        $keys = Query::escape_keys(array_keys($fields));
        $values = Query::escape_values(array_values($fields));
        return 'INSERT INTO `'.$table_name.'` ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')';
    }

    public static function escape_keys($keys, $prefix = '') {
        $result = array();
        foreach ($keys as $key)
            $result[] = '`'.$prefix.$key.'`';
        return $result;
    }
    
    public static function escape_value($value) {
        $arr = Query::escape_values(array($value));
        return $arr[0];
    }
    
    public static function escape_values($values) {
        $result = array();      
        foreach ($values as $value) {
            if (is_bool($value))
                $value = ($value == FALSE)? 0 : 1;
            else if (is_null($value))
                $value = 'NULL';
            else
                $value = "'".mysql_real_escape_string($value)."'";

            $result[] = $value;
        }
        return $result;
    }
    
}

class QueryConstructor {
    private $query = '';
    private $dbf = '';
    
    public function select($class_name) {
        extract(Object::getDBInfo($class_name));
        $this->dbf = $field_prefix;
        
        $this->query .= 'SELECT * FROM `'.$table_name.'` '; 
        return $this;
    }
    
    public function delete($table_name) {
        $this->query .= 'DELETE FROM `'.$table_name.'` ';
        return $this;
    }
    
    public function where() {
        if (func_num_args() == 2)
          $fields = array(func_get_arg(0) => func_get_arg(1));
        else
          $fields = func_get_arg(0);

        $keys = Query::escape_keys(array_keys($fields), $this->dbf);
        $values = Query::escape_values(array_values($fields));
        
        $where_condition = 'WHERE ';
        $where_condition .= array_shift($keys).' = '.array_shift($values);
        
        while ($keys)
            $where_condition .= 'AND '.array_shift($keys).' = '.array_shift($values);
        
        $this->query .= $where_condition;
        return $this;
    }
    
    public function get() {
        return $this->query;
    }
}
*/
?>